﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http.Json;
using System.Reflection;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Dapr.Client;
using Messhall.Framework.AppFilters;
using Messhall.HostService.Proxy.Model;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Messhall.HostService.Proxy
{
    public class DispatchProxyFactory<T> : DispatchProxy
    {
        /// <summary>
        /// 服务文件常量
        /// </summary>
        private const string SERVICE_FILE_PATH = "host-service.json";

        /// <summary>
        /// Dapr客户端
        /// </summary>
        private static DaprClient _daprClient { get; }

        private string _apiUrl
        {
            get
            {
                var customAttributes = _type.CustomAttributes
                    .FirstOrDefault(attribute => attribute.AttributeType.Name == "RouteAttribute")
                    ?.ConstructorArguments[0].Value;
                if (customAttributes == null)
                {
                    throw new Exception("请在接口名注释[Route('')]");
                }

                return customAttributes.ToString();
            }
        }

        static DispatchProxyFactory()
        {
            _daprClient = new DaprClientBuilder().Build();
        }

        private Type _type;

        public DispatchProxyFactory()
        {
            this._type = typeof(T);
        }

        protected override object Invoke(MethodInfo? targetMethod, object?[]? args)
        {
            if (targetMethod == null)
            {
                return Task.CompletedTask;
            }

            var genericTypeArguments = targetMethod.ReturnParameter.ParameterType.GenericTypeArguments.FirstOrDefault();

            var invoke = Task.Run(() => this.DaprInvokeAsync(targetMethod, args));

            Task.WaitAll(invoke);

            if (genericTypeArguments == null)
            {
                return Task.CompletedTask;
            }

            ApiResult invokeResult = invoke.Result;

            if (invokeResult.Data == null)
            {
                return Task.CompletedTask;
            }

            string dataConvertToString = JsonConvert.SerializeObject(invokeResult.Data);

            if (string.IsNullOrWhiteSpace(dataConvertToString))
            {
                return Task.CompletedTask;
            }

            dynamic dataConvertToModel = JsonConvert.DeserializeObject(dataConvertToString, genericTypeArguments);

            return Task.FromResult(dataConvertToModel);
        }

        public async Task<ApiResult> DaprInvokeAsync(MethodInfo targetMethod, object?[]? args)
        {
            try
            {
                var methodName = GetRoute(targetMethod);
                var httpMethod = GetHttpMethod(targetMethod.CustomAttributes);
                var appId = GetAppId();
                var apiAddress = $"{_apiUrl}/{methodName}";

                object data = args != null && args.Any() ? args[0] : args;

                var httpRequestMessage =
                    _daprClient.CreateInvokeMethodRequest<object>(httpMethod, appId, apiAddress, data);

                var httpContent = httpRequestMessage.Content;

                Console.WriteLine($"{httpRequestMessage.RequestUri}---{httpMethod}---{JsonConvert.SerializeObject(data)}");

                //post如果调不通，请检查string 类型是否为null，.net6 [string? != string || string? == null]
                var response = await _daprClient.InvokeMethodWithResponseAsync(httpRequestMessage);

                if (response.IsSuccessStatusCode)
                {
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        var readAsString = await response.Content.ReadAsStringAsync();

                        if (!string.IsNullOrWhiteSpace(readAsString))
                        {
                            var apiResult = JsonConvert.DeserializeObject<ApiResult>(readAsString);

                            if (apiResult?.HttpStatus != HttpStatusCode.OK)
                            {
                                throw new Exception(apiResult?.Message);
                            }

                            return apiResult;
                        }
                    }
                    else
                        throw new Exception($"API调用异常：{response.StatusCode}，Url：{methodName}");
                }
                else
                    throw new Exception(response.ReasonPhrase);

                return null;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                throw e;
            }
        }

        private static string GetRoute(MethodInfo targetMethod)
        {
            var methodName = targetMethod.CustomAttributes
                .FirstOrDefault(attribute => attribute.AttributeType.Name == "RouteAttribute")?.ConstructorArguments[0]
                .Value;
            if (methodName == null)
            {
                //return targetMethod.Name;
                return string.Empty;
            }

            return methodName?.ToString();
        }

        private static HttpMethod GetHttpMethod(IEnumerable<CustomAttributeData> customAttribute)
        {
            HttpMethod httpMethod = null;

            var customAttributeName = customAttribute.Select(custom => custom.AttributeType.Name);

            foreach (var name in customAttributeName)
            {
                httpMethod = name switch
                {
                    "HttpGetAttribute" => HttpMethod.Get,
                    "HttpPostAttribute" => HttpMethod.Post,
                    "HttpPutAttribute" => HttpMethod.Put,
                    "HttpDeleteAttribute" => HttpMethod.Delete,
                    "HttpHeadAttribute" => HttpMethod.Head,
                    "HttpOptionsAttribute" => HttpMethod.Options
                };
                if (httpMethod != null)
                {
                    break;
                }
            }

            return httpMethod;
        }

        private string GetAppId()
        {
            var serviceChannelModels = GetHostAddress();

            var appId = string.Empty;

            foreach (var item in serviceChannelModels)
            {
                if (item.ServiceInterfaceNamespace.Any(name => name.Contains(_type.Namespace)))
                {
                    appId = item.AppId;
                    break;
                }
            }

            if (string.IsNullOrWhiteSpace(appId))
            {
                throw new Exception("未找到服务地址");
            }

            return appId;
        }

        private static List<ServiceChannelModel> GetHostAddress()
        {
            var services = System.IO.File.ReadAllText(SERVICE_FILE_PATH);

            if (string.IsNullOrWhiteSpace(services))
            {
                throw new Exception("host file is null");
            }

            return JsonConvert.DeserializeObject<List<ServiceChannelModel>>(services);
        }
    }


    public class ConvertModel<T>
    {
    }
}